﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Xml.Serialization;

using MiniTwitter.Extensions;
using MiniTwitter.Net.Twitter;

namespace MiniTwitter
{
    [Serializable]
    public class Timeline : PropertyChangedBase
    {
        public Timeline()
        {
            MaxCount = 1000;
            Items = new ObservableCollection<ITwitterItem>();
            View = (ListCollectionView)CollectionViewSource.GetDefaultView(Items);
        }

        private object thisLock = new object();

        private string name;

        [XmlAttribute]
        public string Name
        {
            get { return name; }
            set
            {
                if (name != value)
                {
                    name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        [XmlAttribute]
        public TimelineType Type { get; set; }

        [XmlAttribute]
        public int MaxCount { get; set; }

        private List<Filter> filters;

        [XmlElement("Filter")]
        public List<Filter> Filters
        {
            get
            {
                if (filters == null)
                {
                    filters = new List<Filter>();
                }
                return filters;
            }
            set { filters = value; }
        }

        [XmlIgnore]
        public ListCollectionView View { get; private set; }

        [XmlIgnore]
        public ObservableCollection<ITwitterItem> Items { get; private set; }

        public void Update<T>(IEnumerable<T> appendItems) where T : ITwitterItem
        {
            lock (thisLock)
            {
                if (appendItems == null)
                {
                    return;
                }
                foreach (var item in Items)
                {
                    item.UpdateRelativeTime();
                }
                foreach (var item in appendItems.Where(x => !Items.Contains(x) && IsFilterMatch(x)))
                {
                    Items.Add(item);
                }
                if (Items.Count > MaxCount)
                {
                    var deleteItems = (from p in Items orderby p.CreatedAt where !p.IsNewest select p).Take(Items.Count - MaxCount);
                    foreach (var item in deleteItems)
                    {
                        Items.Remove(item);
                    }
                }
                View.Refresh();
            }
        }

        public void Remove(ITwitterItem removeItem)
        {
            lock (thisLock)
            {
                if (removeItem == null)
                {
                    return;
                }
                if (Items.Remove(removeItem))
                {
                    View.Refresh();
                }
            }
        }

        public void RemoveAll(Predicate<ITwitterItem> match)
        {
            lock (thisLock)
            {
                for (int i = 0; i < Items.Count; i++)
                {
                    if (match(Items[i]))
                    {
                        Items.RemoveAt(i--);
                    }
                }
                View.Refresh();
            }
        }

        public void Clear()
        {
            lock (thisLock)
            {
                View.Filter = null;
                Items.Clear();
                View.Refresh();
            }
        }

        public T[] Normalize<T>(IEnumerable<T> items) where T : ITwitterItem
        {
            lock (thisLock)
            {
                if (items == null)
                {
                    return null;
                }
                return items.Where(x => !Items.Contains(x) && IsFilterMatch(x)).ToArray();
            }
        }

        public void Sort(ListSortCategory category, ListSortDirection direction)
        {
            lock (thisLock)
            {
                View.SortDescriptions.Clear();
                View.SortDescriptions.Add(new SortDescription(category.ToPropertyPath(), direction));
                if (category != ListSortCategory.CreatedAt)
                {
                    View.SortDescriptions.Add(new SortDescription(ListSortCategory.CreatedAt.ToPropertyPath(), direction));
                }
                View.SortDescriptions.Add(new SortDescription(ListSortCategory.ID.ToPropertyPath(), direction));
            }
        }

        public void Search(string term)
        {
            lock (thisLock)
            {
                if (term.IsNullOrEmpty())
                {
                    View.Filter = null;
                }
                else
                {
                    View.Filter = state =>
                        {
                            var item = (ITwitterItem)state;
                            return item.Text.Contains(term) || item.Sender.ScreenName.Contains(term);
                        };
                }
                View.Refresh();
            }
        }

        private bool IsFilterMatch(ITwitterItem item)
        {
            return Filters.Count == 0 || Filters.Any(filter => filter.Process(item));
        }
    }
}